home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / Direct3D / ProgressiveMesh / ProgressiveMesh.cpp next >
Encoding:
C/C++ Source or Header  |  2004-09-28  |  33.7 KB  |  769 lines

  1. //--------------------------------------------------------------------------------------
  2. // File: ProgressiveMesh.cpp
  3. //
  4. // Starting point for new Direct3D applications
  5. //
  6. // Copyright (c) Microsoft Corporation. All rights reserved.
  7. //--------------------------------------------------------------------------------------
  8. #include "dxstdafx.h"
  9. #include "resource.h"
  10.  
  11. //#define DEBUG_VS   // Uncomment this line to debug vertex shaders 
  12. //#define DEBUG_PS   // Uncomment this line to debug pixel shaders 
  13.  
  14. #define MESHFILENAME L"dwarf\\dwarf.x"
  15.  
  16.  
  17. //--------------------------------------------------------------------------------------
  18. // Global variables
  19. //--------------------------------------------------------------------------------------
  20. ID3DXFont*              g_pFont = NULL;         // Font for drawing text
  21. ID3DXSprite*            g_pTextSprite = NULL;   // Sprite for batching draw text calls
  22. ID3DXEffect*            g_pEffect = NULL;       // D3DX effect interface
  23. CModelViewerCamera      g_Camera;               // A model viewing camera
  24. bool                    g_bShowHelp = true;     // If true, it renders the UI control text
  25. CDXUTDialog             g_HUD;                  // dialog for standard controls
  26. CDXUTDialog             g_SampleUI;             // dialog for sample specific controls
  27. ID3DXPMesh**            g_ppPMeshes = NULL;
  28. ID3DXPMesh*             g_pPMeshFull = NULL;
  29. DWORD                   g_cPMeshes = 0;
  30. DWORD                   g_iPMeshCur;
  31. D3DMATERIAL9*           g_mtrlMeshMaterials = NULL;
  32. LPDIRECT3DTEXTURE9*     g_ppMeshTextures = NULL;// Array of textures, entries are NULL if no texture specified
  33. DWORD                   g_dwNumMaterials = 0;   // Number of materials
  34. D3DXMATRIXA16           g_mWorldCenter;
  35. D3DXVECTOR3             g_vObjectCenter;        // Center of bounding sphere of object
  36. FLOAT                   g_fObjectRadius;        // Radius of bounding sphere of object
  37. BOOL                    g_bShowOptimized = true;
  38.  
  39.  
  40. //--------------------------------------------------------------------------------------
  41. // UI control IDs
  42. //--------------------------------------------------------------------------------------
  43. #define IDC_TOGGLEFULLSCREEN    1
  44. #define IDC_TOGGLEREF           3
  45. #define IDC_CHANGEDEVICE        4
  46. #define IDC_DETAIL              5
  47. #define IDC_DETAILLABEL         6
  48. #define IDC_USEOPTIMIZED        7
  49.  
  50.  
  51.  
  52. //--------------------------------------------------------------------------------------
  53. // Forward declarations 
  54. //--------------------------------------------------------------------------------------
  55. bool    CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, D3DFORMAT BackBufferFormat, bool bWindowed );
  56. void    CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps );
  57. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  58. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc );
  59. void    CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  60. void    CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime );
  61. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing );
  62. void    CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown  );
  63. void    CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl );
  64. void    CALLBACK OnLostDevice();
  65. void    CALLBACK OnDestroyDevice();
  66.  
  67. void    InitApp();
  68. void    RenderText();
  69. void    SetNumVertices( DWORD dwNumVertices );
  70.  
  71.  
  72. //--------------------------------------------------------------------------------------
  73. // Entry point to the program. Initializes everything and goes into a message processing 
  74. // loop. Idle time is used to render the scene.
  75. //--------------------------------------------------------------------------------------
  76. INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
  77. {
  78.     // Set the callback functions. These functions allow the sample framework to notify
  79.     // the application about device changes, user input, and windows messages.  The 
  80.     // callbacks are optional so you need only set callbacks for events you're interested 
  81.     // in. However, if you don't handle the device reset/lost callbacks then the sample 
  82.     // framework won't be able to reset your device since the application must first 
  83.     // release all device resources before resetting.  Likewise, if you don't handle the 
  84.     // device created/destroyed callbacks then the sample framework won't be able to 
  85.     // recreate your device resources.
  86.     DXUTSetCallbackDeviceCreated( OnCreateDevice );
  87.     DXUTSetCallbackDeviceReset( OnResetDevice );
  88.     DXUTSetCallbackDeviceLost( OnLostDevice );
  89.     DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
  90.     DXUTSetCallbackMsgProc( MsgProc );
  91.     DXUTSetCallbackKeyboard( KeyboardProc );
  92.     DXUTSetCallbackFrameRender( OnFrameRender );
  93.     DXUTSetCallbackFrameMove( OnFrameMove );
  94.  
  95.     // Show the cursor and clip it when in full screen
  96.     DXUTSetCursorSettings( true, true );
  97.  
  98.     InitApp();
  99.  
  100.     // Initialize the sample framework and create the desired Win32 window and Direct3D 
  101.     // device for the application. Calling each of these functions is optional, but they
  102.     // allow you to set several options which control the behavior of the framework.
  103.     DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
  104.     DXUTCreateWindow( L"ProgressiveMesh: Using Progressive Meshes in Direct3D" );
  105.     DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );
  106.  
  107.     // Pass control to the sample framework for handling the message pump and 
  108.     // dispatching render calls. The sample framework will call your FrameMove 
  109.     // and FrameRender callback when there is idle time between handling window messages.
  110.     DXUTMainLoop();
  111.  
  112.     // Perform any application-level cleanup here. Direct3D device resources are released within the
  113.     // appropriate callback functions and therefore don't require any cleanup code here.
  114.  
  115.     return DXUTGetExitCode();
  116. }
  117.  
  118.  
  119. //--------------------------------------------------------------------------------------
  120. // Initialize the app 
  121. //--------------------------------------------------------------------------------------
  122. void InitApp()
  123. {
  124.     // Initialize dialogs
  125.     g_HUD.SetCallback( OnGUIEvent ); int iY = 10; 
  126.     g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 35, iY, 125, 22 );
  127.     g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 35, iY += 24, 125, 22 );
  128.     g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 35, iY += 24, 125, 22 );
  129.  
  130.     g_SampleUI.EnableKeyboardInput( true );
  131.     g_SampleUI.SetCallback( OnGUIEvent ); iY = 10;
  132.     g_SampleUI.AddStatic( IDC_DETAILLABEL, L"Level of Detail:", 0, iY, 200, 16 );
  133.     g_SampleUI.AddCheckBox( IDC_USEOPTIMIZED, L"Use optimized mesh", 50, iY, 200, 20, true );
  134.     g_SampleUI.AddSlider( IDC_DETAIL, 10, iY += 16, 200, 16, 4, 4, 4 );
  135.  
  136.     g_Camera.SetButtonMasks( MOUSE_LEFT_BUTTON, MOUSE_WHEEL, 0 );
  137. }
  138.  
  139.  
  140. //--------------------------------------------------------------------------------------
  141. // Called during device initialization, this code checks the device for some 
  142. // minimum set of capabilities, and rejects those that don't pass by returning false.
  143. //--------------------------------------------------------------------------------------
  144. bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat, 
  145.                                   D3DFORMAT BackBufferFormat, bool bWindowed )
  146. {
  147.     // Skip backbuffer formats that don't support alpha blending
  148.     IDirect3D9* pD3D = DXUTGetD3DObject(); 
  149.     if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType,
  150.                     AdapterFormat, D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, 
  151.                     D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
  152.         return false;
  153.  
  154.     // Must support pixel shader 1.1
  155.     if( pCaps->PixelShaderVersion < D3DPS_VERSION( 1, 1 ) )
  156.         return false;
  157.  
  158.     return true;
  159. }
  160.  
  161.  
  162. //--------------------------------------------------------------------------------------
  163. // This callback function is called immediately before a device is created to allow the 
  164. // application to modify the device settings. The supplied pDeviceSettings parameter 
  165. // contains the settings that the framework has selected for the new device, and the 
  166. // application can make any desired changes directly to this structure.  Note however that 
  167. // the sample framework will not correct invalid device settings so care must be taken 
  168. // to return valid device settings, otherwise IDirect3D9::CreateDevice() will fail.  
  169. //--------------------------------------------------------------------------------------
  170. void CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps )
  171. {
  172.     // If device doesn't support HW T&L or doesn't support 1.1 vertex shaders in HW 
  173.     // then switch to SWVP.
  174.     if( (pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0 ||
  175.          pCaps->VertexShaderVersion < D3DVS_VERSION(1,1) )
  176.     {
  177.         pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  178.     }
  179.     else
  180.     {
  181.         pDeviceSettings->BehaviorFlags = D3DCREATE_HARDWARE_VERTEXPROCESSING;
  182.     }
  183.  
  184.     // This application is designed to work on a pure device by not using 
  185.     // IDirect3D9::Get*() methods, so create a pure device if supported and using HWVP.
  186.     if ((pCaps->DevCaps & D3DDEVCAPS_PUREDEVICE) != 0 && 
  187.         (pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) != 0 )
  188.         pDeviceSettings->BehaviorFlags |= D3DCREATE_PUREDEVICE;
  189.  
  190.     // Debugging vertex shaders requires either REF or software vertex processing 
  191.     // and debugging pixel shaders requires REF.  
  192. #ifdef DEBUG_VS
  193.     if( pDeviceSettings->DeviceType != D3DDEVTYPE_REF )
  194.     {
  195.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_HARDWARE_VERTEXPROCESSING;
  196.         pDeviceSettings->BehaviorFlags &= ~D3DCREATE_PUREDEVICE;                            
  197.         pDeviceSettings->BehaviorFlags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  198.     }
  199. #endif
  200. #ifdef DEBUG_PS
  201.     pDeviceSettings->DeviceType = D3DDEVTYPE_REF;
  202. #endif
  203. }
  204.  
  205.  
  206. void SetNumVertices( DWORD dwNumVertices )
  207. {
  208.     g_pPMeshFull->SetNumVertices( dwNumVertices );
  209.  
  210.     // If current pm valid for desired value, then set the number of vertices directly
  211.     if( ( dwNumVertices >= g_ppPMeshes[g_iPMeshCur]->GetMinVertices() ) &&
  212.         ( dwNumVertices <= g_ppPMeshes[g_iPMeshCur]->GetMaxVertices() ) )
  213.     {
  214.         g_ppPMeshes[g_iPMeshCur]->SetNumVertices( dwNumVertices );
  215.     }
  216.     else  // Search for the right one
  217.     {
  218.         g_iPMeshCur = g_cPMeshes - 1;
  219.  
  220.         // Look for the correct "bin"
  221.         while( g_iPMeshCur > 0 )
  222.         {
  223.             // If number of vertices is less than current max then we found one to fit
  224.             if( dwNumVertices >= g_ppPMeshes[g_iPMeshCur]->GetMinVertices() )
  225.                 break;
  226.  
  227.             g_iPMeshCur -= 1;
  228.         }
  229.  
  230.         // Set the vertices on the newly selected mesh
  231.         g_ppPMeshes[g_iPMeshCur]->SetNumVertices( dwNumVertices );
  232.     }
  233. }
  234.  
  235.  
  236. //--------------------------------------------------------------------------------------
  237. // This callback function will be called immediately after the Direct3D device has been 
  238. // created, which will happen during application initialization and windowed/full screen 
  239. // toggles. This is the best location to create D3DPOOL_MANAGED resources since these 
  240. // resources need to be reloaded whenever the device is destroyed. Resources created  
  241. // here should be released in the OnDestroyDevice callback. 
  242. //--------------------------------------------------------------------------------------
  243. HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  244. {
  245.     HRESULT hr;
  246.  
  247.     // Initialize the font
  248.     V_RETURN( D3DXCreateFont( pd3dDevice, 15, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, 
  249.                          OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, 
  250.                          L"Arial", &g_pFont ) );
  251.  
  252.     // Define DEBUG_VS and/or DEBUG_PS to debug vertex and/or pixel shaders with the 
  253.     // shader debugger. Debugging vertex shaders requires either REF or software vertex 
  254.     // processing, and debugging pixel shaders requires REF.  The 
  255.     // D3DXSHADER_FORCE_*_SOFTWARE_NOOPT flag improves the debug experience in the 
  256.     // shader debugger.  It enables source level debugging, prevents instruction 
  257.     // reordering, prevents dead code elimination, and forces the compiler to compile 
  258.     // against the next higher available software target, which ensures that the 
  259.     // unoptimized shaders do not exceed the shader model limitations.  Setting these 
  260.     // flags will cause slower rendering since the shaders will be unoptimized and 
  261.     // forced into software.  See the DirectX documentation for more information about 
  262.     // using the shader debugger.
  263.     DWORD dwShaderFlags = 0;
  264.     #ifdef DEBUG_VS
  265.         dwShaderFlags |= D3DXSHADER_FORCE_VS_SOFTWARE_NOOPT;
  266.     #endif
  267.     #ifdef DEBUG_PS
  268.         dwShaderFlags |= D3DXSHADER_FORCE_PS_SOFTWARE_NOOPT;
  269.     #endif
  270.  
  271.     // Read the D3DX effect file
  272.     WCHAR str[MAX_PATH];
  273.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, L"ProgressiveMesh.fx" ) );
  274.  
  275.     // If this fails, there should be debug output as to 
  276.     // they the .fx file failed to compile
  277.     V_RETURN( D3DXCreateEffectFromFile( pd3dDevice, str, NULL, NULL, dwShaderFlags, 
  278.                                         NULL, &g_pEffect, NULL ) );
  279.  
  280.     V_RETURN( g_pEffect->SetTechnique( "RenderScene" ) );
  281.  
  282.     // Load the mesh
  283.     LPD3DXBUFFER pAdjacencyBuffer = NULL;
  284.     LPD3DXBUFFER pD3DXMtrlBuffer = NULL;
  285.     D3DXMATERIAL* d3dxMaterials;
  286.     DWORD        dw32BitFlag;
  287.     LPD3DXMESH   pMesh = NULL;
  288.     LPD3DXPMESH  pPMesh = NULL;
  289.  
  290.     V_RETURN( DXUTFindDXSDKMediaFileCch( str, MAX_PATH, MESHFILENAME ) );
  291.     V_RETURN( D3DXLoadMeshFromX( str, D3DXMESH_MANAGED, pd3dDevice,
  292.                                  &pAdjacencyBuffer, &pD3DXMtrlBuffer, NULL,
  293.                                  &g_dwNumMaterials, &pMesh ) );
  294.  
  295.     // Change the current directory to the mesh's directory so we can
  296.     // find the textures.
  297.     WCHAR* pLastSlash = wcsrchr( str, L'\\' );
  298.     if( pLastSlash )
  299.         *(pLastSlash + 1) = 0;
  300.     WCHAR strCWD[MAX_PATH];
  301.     GetCurrentDirectory( MAX_PATH, strCWD );
  302.     SetCurrentDirectory( str );
  303.  
  304.     dw32BitFlag = ( pMesh->GetOptions() & D3DXMESH_32BIT );
  305.  
  306.     // Perform simple cleansing operations on mesh
  307.     LPD3DXMESH pTempMesh;
  308.     if( FAILED( hr = D3DXCleanMesh( D3DXCLEAN_SIMPLIFICATION, pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), &pTempMesh, 
  309.                                     (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL ) ) )
  310.     {
  311.         g_dwNumMaterials = 0;
  312.         goto End;
  313.     }
  314.     SAFE_RELEASE( pMesh );
  315.     pMesh = pTempMesh;
  316.  
  317.     // Perform a weld to try and remove excess vertices.
  318.     // Weld the mesh using all epsilons of 0.0f.  A small epsilon like 1e-6 works well too
  319.     D3DXWELDEPSILONS Epsilons;
  320.     ZeroMemory( &Epsilons, sizeof(D3DXWELDEPSILONS) );
  321.     if( FAILED( hr = D3DXWeldVertices( pMesh, 0, &Epsilons,
  322.                                        (DWORD*)pAdjacencyBuffer->GetBufferPointer(),
  323.                                        (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL, NULL ) ) )
  324.     {
  325.         g_dwNumMaterials = 0;
  326.         goto End;
  327.     }
  328.  
  329.     // Verify validity of mesh for simplification
  330.     if( FAILED( hr = D3DXValidMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(), NULL ) ) )
  331.     {
  332.         g_dwNumMaterials = 0;
  333.         goto End;
  334.     }
  335.  
  336.     // Allocate a material/texture arrays
  337.     d3dxMaterials = (D3DXMATERIAL*)pD3DXMtrlBuffer->GetBufferPointer();
  338.     g_mtrlMeshMaterials = new D3DMATERIAL9[g_dwNumMaterials];
  339.     g_ppMeshTextures    = new LPDIRECT3DTEXTURE9[g_dwNumMaterials];
  340.  
  341.     // Copy the materials and load the textures
  342.     for( UINT i = 0; i < g_dwNumMaterials; i++ )
  343.     {
  344.         g_mtrlMeshMaterials[i] = d3dxMaterials[i].MatD3D;
  345.         g_mtrlMeshMaterials[i].Ambient = g_mtrlMeshMaterials[i].Diffuse;
  346.  
  347.         // Find the path to the texture and create that texture
  348.         MultiByteToWideChar( CP_ACP, 0, d3dxMaterials[i].pTextureFilename, -1, str, MAX_PATH );
  349.         str[MAX_PATH - 1] = L'\0';
  350.         if( FAILED( D3DXCreateTextureFromFile( pd3dDevice, str, &g_ppMeshTextures[i] ) ) )
  351.             g_ppMeshTextures[i] = NULL;
  352.     }
  353.     SAFE_RELEASE( pD3DXMtrlBuffer );
  354.  
  355.     // Restore the current directory
  356.     SetCurrentDirectory( strCWD );
  357.  
  358.     // Lock the vertex buffer, to generate a simple bounding sphere
  359.     LPDIRECT3DVERTEXBUFFER9 pVertexBuffer = NULL;
  360.     void* pVertices;
  361.     hr = pMesh->GetVertexBuffer( &pVertexBuffer );
  362.     if( FAILED(hr) )
  363.         goto End;
  364.  
  365.     hr = pVertexBuffer->Lock( 0, 0, &pVertices, D3DLOCK_NOSYSLOCK );
  366.     if( FAILED(hr) )
  367.         goto End;
  368.  
  369.     hr = D3DXComputeBoundingSphere( (D3DXVECTOR3*)pVertices, pMesh->GetNumVertices(),
  370.                                     D3DXGetFVFVertexSize(pMesh->GetFVF()),
  371.                                     &g_vObjectCenter, &g_fObjectRadius );
  372.     pVertexBuffer->Unlock();
  373.     SAFE_RELEASE( pVertexBuffer );
  374.  
  375.     if( FAILED(hr) )
  376.         goto End;
  377.  
  378.     {
  379.         D3DXMatrixTranslation( &g_mWorldCenter, -g_vObjectCenter.x,
  380.                                                 -g_vObjectCenter.y,
  381.                                                 -g_vObjectCenter.z );
  382.         D3DXMATRIXA16 m;
  383.         D3DXMatrixScaling( &m, 2.0f / g_fObjectRadius,
  384.                             2.0f / g_fObjectRadius,
  385.                             2.0f / g_fObjectRadius );
  386.         D3DXMatrixMultiply( &g_mWorldCenter, &g_mWorldCenter, &m );
  387.     }
  388.  
  389.     // If the mesh is missing normals, generate them.
  390.     if ( !( pMesh->GetFVF() & D3DFVF_NORMAL ) )
  391.     {
  392.         hr = pMesh->CloneMeshFVF( dw32BitFlag | D3DXMESH_MANAGED, pMesh->GetFVF() | D3DFVF_NORMAL,
  393.                                   pd3dDevice, &pTempMesh );
  394.         if( FAILED(hr) )
  395.             goto End;
  396.  
  397.         D3DXComputeNormals( pTempMesh, NULL );
  398.  
  399.         pMesh->Release();
  400.         pMesh = pTempMesh;
  401.     }
  402.  
  403.     // Generate progressive meshes
  404.  
  405.     hr = D3DXGeneratePMesh( pMesh, (DWORD*)pAdjacencyBuffer->GetBufferPointer(),
  406.                             NULL, NULL, 1, D3DXMESHSIMP_VERTEX, &pPMesh );
  407.     if( FAILED(hr) )
  408.         goto End;
  409.  
  410.     DWORD cVerticesMin = pPMesh->GetMinVertices();
  411.     DWORD cVerticesMax = pPMesh->GetMaxVertices();
  412.  
  413.     DWORD cVerticesPerMesh = ( cVerticesMax - cVerticesMin + 10 ) / 10;
  414.  
  415.     g_cPMeshes = max( 1, (DWORD)ceil( (cVerticesMax - cVerticesMin + 1) / (float)cVerticesPerMesh ) );
  416.     g_ppPMeshes = new LPD3DXPMESH[g_cPMeshes];
  417.     if( g_ppPMeshes == NULL )
  418.     {
  419.         hr = E_OUTOFMEMORY;
  420.         goto End;
  421.     }
  422.     ZeroMemory( g_ppPMeshes, sizeof(LPD3DXPMESH) * g_cPMeshes );
  423.  
  424.     // Clone full size pmesh
  425.     hr = pPMesh->ClonePMeshFVF( D3DXMESH_MANAGED | D3DXMESH_VB_SHARE, pPMesh->GetFVF(), pd3dDevice, &g_pPMeshFull );
  426.     if( FAILED(hr) )
  427.         goto End;
  428.  
  429.     // Clone all the separate pmeshes
  430.     for( UINT iPMesh = 0; iPMesh < g_cPMeshes; iPMesh++ )
  431.     {
  432.         hr = pPMesh->ClonePMeshFVF( D3DXMESH_MANAGED | D3DXMESH_VB_SHARE, pPMesh->GetFVF(), pd3dDevice, &g_ppPMeshes[iPMesh] );
  433.         if( FAILED(hr) )
  434.             goto End;
  435.  
  436.         // Trim to appropriate space
  437.         hr = g_ppPMeshes[iPMesh]->TrimByVertices( cVerticesMin + cVerticesPerMesh * iPMesh, cVerticesMin + cVerticesPerMesh * (iPMesh+1), NULL, NULL);
  438.         if( FAILED(hr) )
  439.             goto End;
  440.  
  441.         hr = g_ppPMeshes[iPMesh]->OptimizeBaseLOD( D3DXMESHOPT_VERTEXCACHE, NULL );
  442.         if( FAILED(hr) )
  443.             goto End;
  444.     }
  445.  
  446.     // Set current to be maximum number of vertices
  447.     g_iPMeshCur = g_cPMeshes - 1;
  448.     hr = g_ppPMeshes[g_iPMeshCur]->SetNumVertices( cVerticesMax );
  449.     if( FAILED(hr) )
  450.         goto End;
  451.  
  452.     hr = g_pPMeshFull->SetNumVertices( cVerticesMax );
  453.     if( FAILED(hr) )
  454.         goto End;
  455.  
  456.     // Set up the slider to reflect the vertices range the mesh has
  457.     g_SampleUI.GetSlider( IDC_DETAIL )->SetRange( g_ppPMeshes[0]->GetMinVertices(), g_ppPMeshes[g_cPMeshes-1]->GetMaxVertices() );
  458.     g_SampleUI.GetSlider( IDC_DETAIL )->SetValue( g_ppPMeshes[g_iPMeshCur]->GetNumVertices() );
  459.  
  460.     // Setup the camera's view parameters
  461.     {
  462.         D3DXVECTOR3 vecEye(0.0f, 0.0f, -5.0f);
  463.         D3DXVECTOR3 vecAt (0.0f, 0.0f, -0.0f);
  464.         g_Camera.SetViewParams( &vecEye, &vecAt );
  465.     }
  466.  
  467. End:
  468.     SAFE_RELEASE( pAdjacencyBuffer );
  469.     SAFE_RELEASE( pD3DXMtrlBuffer );
  470.     SAFE_RELEASE( pMesh );
  471.     SAFE_RELEASE( pPMesh );
  472.  
  473.     if( FAILED(hr) )
  474.     {
  475.         for( UINT iPMesh = 0; iPMesh < g_cPMeshes; iPMesh++ )
  476.             SAFE_RELEASE( g_ppPMeshes[iPMesh] );
  477.  
  478.         delete[] g_ppPMeshes;
  479.         g_cPMeshes = 0;
  480.         g_ppPMeshes = NULL;
  481.         SAFE_RELEASE( g_pPMeshFull )
  482.     }
  483.  
  484.     return hr;
  485. }
  486.  
  487.  
  488. //--------------------------------------------------------------------------------------
  489. // This callback function will be called immediately after the Direct3D device has been 
  490. // reset, which will happen after a lost device scenario. This is the best location to 
  491. // create D3DPOOL_DEFAULT resources since these resources need to be reloaded whenever 
  492. // the device is lost. Resources created here should be released in the OnLostDevice 
  493. // callback. 
  494. //--------------------------------------------------------------------------------------
  495. HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice, 
  496.                                 const D3DSURFACE_DESC* pBackBufferSurfaceDesc )
  497. {
  498.     HRESULT hr;
  499.  
  500.     if( g_pFont )
  501.         V_RETURN( g_pFont->OnResetDevice() );
  502.     if( g_pEffect )
  503.         V_RETURN( g_pEffect->OnResetDevice() );
  504.  
  505.     // Create a sprite to help batch calls when drawing many lines of text
  506.     V_RETURN( D3DXCreateSprite( pd3dDevice, &g_pTextSprite ) );
  507.  
  508.     // Setup the camera's projection parameters
  509.     float fAspectRatio = pBackBufferSurfaceDesc->Width / (FLOAT)pBackBufferSurfaceDesc->Height;
  510.     g_Camera.SetProjParams( D3DX_PI/4, fAspectRatio, 0.1f, 1000.0f );
  511.     g_Camera.SetWindow( pBackBufferSurfaceDesc->Width, pBackBufferSurfaceDesc->Height );
  512.  
  513.     g_HUD.SetLocation( pBackBufferSurfaceDesc->Width-170, 0 );
  514.     g_HUD.SetSize( 170, 170 );
  515.     g_SampleUI.SetLocation( 0, pBackBufferSurfaceDesc->Height-50 );
  516.     g_SampleUI.SetSize( pBackBufferSurfaceDesc->Width, 50 );
  517.     g_SampleUI.GetControl( IDC_DETAILLABEL )->SetLocation( ( pBackBufferSurfaceDesc->Width - 200 ) / 2, 10 );
  518.     g_SampleUI.GetControl( IDC_USEOPTIMIZED )->SetLocation( pBackBufferSurfaceDesc->Width - 130, 5 );
  519.     g_SampleUI.GetControl( IDC_DETAIL )->SetSize( pBackBufferSurfaceDesc->Width - 20, 16 );
  520.  
  521.     return S_OK;
  522. }
  523.  
  524.  
  525. //--------------------------------------------------------------------------------------
  526. // This callback function will be called once at the beginning of every frame. This is the
  527. // best location for your application to handle updates to the scene, but is not 
  528. // intended to contain actual rendering calls, which should instead be placed in the 
  529. // OnFrameRender callback.  
  530. //--------------------------------------------------------------------------------------
  531. void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  532. {
  533.     // Update the camera's position based on user input 
  534.     g_Camera.FrameMove( fElapsedTime );
  535. }
  536.  
  537.  
  538. //--------------------------------------------------------------------------------------
  539. // This callback function will be called at the end of every frame to perform all the 
  540. // rendering calls for the scene, and it will also be called if the window needs to be 
  541. // repainted. After this function has returned, the sample framework will call 
  542. // IDirect3DDevice9::Present to display the contents of the next buffer in the swap chain
  543. //--------------------------------------------------------------------------------------
  544. void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime )
  545. {
  546.     HRESULT hr;
  547.     D3DXMATRIXA16 mWorld;
  548.     D3DXMATRIXA16 mView;
  549.     D3DXMATRIXA16 mProj;
  550.     D3DXMATRIXA16 mWorldViewProjection;
  551.     
  552.     // Clear the render target and the zbuffer 
  553.     V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 66, 75, 121), 1.0f, 0) );
  554.  
  555.     // Render the scene
  556.     if( SUCCEEDED( pd3dDevice->BeginScene() ) )
  557.     {
  558.         // Get the projection & view matrix from the camera class
  559.         mWorld = g_mWorldCenter * *g_Camera.GetWorldMatrix();
  560.         mProj = *g_Camera.GetProjMatrix();
  561.         mView = *g_Camera.GetViewMatrix();
  562.  
  563.         mWorldViewProjection = mWorld * mView * mProj;
  564.  
  565.         if( g_ppPMeshes )
  566.         {
  567.             // Update the effect's variables.  Instead of using strings, it would 
  568.             // be more efficient to cache a handle to the parameter by calling 
  569.             // ID3DXEffect::GetParameterByName
  570.             V( g_pEffect->SetMatrix( "g_mWorldViewProjection", &mWorldViewProjection ) );
  571.             V( g_pEffect->SetMatrix( "g_mWorld", &mWorld ) );
  572.             // Set and draw each of the materials in the mesh
  573.             for( DWORD i = 0; i < g_dwNumMaterials; i++ )
  574.             {
  575.                 V( g_pEffect->SetVector( "g_vDiffuse", (D3DXVECTOR4*)&g_mtrlMeshMaterials[i] ) );
  576.                 V( g_pEffect->SetTexture( "g_txScene", g_ppMeshTextures[i] ) );
  577.                 UINT cPasses;
  578.                 V( g_pEffect->Begin( &cPasses, 0 ) );
  579.                 for( UINT p = 0; p < cPasses; ++p )
  580.                 {
  581.                     V( g_pEffect->BeginPass( p ) );
  582.                     if( g_bShowOptimized )
  583.                     {
  584.                         V( g_ppPMeshes[g_iPMeshCur]->DrawSubset( i ) );
  585.                     }
  586.                     else
  587.                     {
  588.                         V( g_pPMeshFull->DrawSubset( i ) );
  589.                     }
  590.                     V( g_pEffect->EndPass() );
  591.                 }
  592.                 V( g_pEffect->End() );
  593.             }
  594.         }
  595.  
  596.         RenderText();
  597.         V( g_HUD.OnRender( fElapsedTime ) );
  598.         V( g_SampleUI.OnRender( fElapsedTime ) );
  599.  
  600.         V( pd3dDevice->EndScene() );
  601.     }
  602. }
  603.  
  604.  
  605. //--------------------------------------------------------------------------------------
  606. // Render the help and statistics text. This function uses the ID3DXFont interface for 
  607. // efficient text rendering.
  608. //--------------------------------------------------------------------------------------
  609. void RenderText()
  610. {
  611.     // The helper object simply helps keep track of text position, and color
  612.     // and then it calls pFont->DrawText( m_pSprite, strMsg, -1, &rc, DT_NOCLIP, m_clr );
  613.     // If NULL is passed in as the sprite object, then it will work however the 
  614.     // pFont->DrawText() will not be batched together.  Batching calls will improves performance.
  615.     const D3DSURFACE_DESC* pd3dsdBackBuffer = DXUTGetBackBufferSurfaceDesc();
  616.     CDXUTTextHelper txtHelper( g_pFont, g_pTextSprite, 15 );
  617.  
  618.     // Output statistics
  619.     txtHelper.Begin();
  620.     txtHelper.SetInsertionPos( 5, 5 );
  621.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
  622.     txtHelper.DrawTextLine( DXUTGetFrameStats() );
  623.     txtHelper.DrawTextLine( DXUTGetDeviceStats() );
  624.  
  625.     txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
  626.     if( g_bShowOptimized )
  627.         txtHelper.DrawFormattedTextLine( L"Using optimized mesh %d of %d\n"
  628.                                         L"Current mesh vertices range: %u / %u\n"
  629.                                         L"Absolute vertices range: %u / %u\n"
  630.                                         L"Current vertices: %d\n",
  631.                                         g_iPMeshCur + 1, g_cPMeshes,
  632.                                         g_ppPMeshes[g_iPMeshCur]->GetMinVertices(),
  633.                                         g_ppPMeshes[g_iPMeshCur]->GetMaxVertices(),
  634.                                         g_ppPMeshes[0]->GetMinVertices(),
  635.                                         g_ppPMeshes[g_cPMeshes-1]->GetMaxVertices(),
  636.                                         g_ppPMeshes[g_iPMeshCur]->GetNumVertices() );
  637.     else
  638.         txtHelper.DrawFormattedTextLine( L"Using unoptimized mesh\n"
  639.                                         L"Mesh vertices range: %u / %u\n"
  640.                                         L"Current vertices: %d\n",
  641.                                         g_pPMeshFull->GetMinVertices(),
  642.                                         g_pPMeshFull->GetMaxVertices(),
  643.                                         g_pPMeshFull->GetNumVertices() );
  644.  
  645.     // Draw help
  646.     if( g_bShowHelp )
  647.     {
  648.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*7 );
  649.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  650.         txtHelper.DrawTextLine( L"Controls (F1 to hide):" );
  651.  
  652.         txtHelper.SetInsertionPos( 40, pd3dsdBackBuffer->Height-15*6 );
  653.         txtHelper.DrawTextLine( L"Rotate mesh: Left click drag\n"
  654.                                 L"Zoom: mouse wheel\n"
  655.                                 L"Quit: ESC" );
  656.     }
  657.     else
  658.     {
  659.         txtHelper.SetInsertionPos( 10, pd3dsdBackBuffer->Height-15*4 );
  660.         txtHelper.SetForegroundColor( D3DXCOLOR( 1.0f, 0.75f, 0.0f, 1.0f ) );
  661.         txtHelper.DrawTextLine( L"Press F1 for help" );
  662.     }
  663.     txtHelper.End();
  664. }
  665.  
  666.  
  667. //--------------------------------------------------------------------------------------
  668. // Before handling window messages, the sample framework passes incoming windows 
  669. // messages to the application through this callback function. If the application sets 
  670. // *pbNoFurtherProcessing to TRUE, then the sample framework will not process this message.
  671. //--------------------------------------------------------------------------------------
  672. LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing )
  673. {
  674.     // Give the dialogs a chance to handle the message first
  675.     *pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
  676.     if( *pbNoFurtherProcessing )
  677.         return 0;
  678.     *pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
  679.     if( *pbNoFurtherProcessing )
  680.         return 0;
  681.  
  682.     // Pass all remaining windows messages to camera so it can respond to user input
  683.     g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
  684.  
  685.     return 0;
  686. }
  687.  
  688.  
  689. //--------------------------------------------------------------------------------------
  690. // As a convenience, the sample framework inspects the incoming windows messages for
  691. // keystroke messages and decodes the message parameters to pass relevant keyboard
  692. // messages to the application.  The framework does not remove the underlying keystroke 
  693. // messages, which are still passed to the application's MsgProc callback.
  694. //--------------------------------------------------------------------------------------
  695. void CALLBACK KeyboardProc( UINT nChar, bool bKeyDown, bool bAltDown )
  696. {
  697.     if( bKeyDown )
  698.     {
  699.         switch( nChar )
  700.         {
  701.             case VK_F1: g_bShowHelp = !g_bShowHelp; break;
  702.         }
  703.     }
  704. }
  705.  
  706.  
  707. //--------------------------------------------------------------------------------------
  708. // Handles the GUI events
  709. //--------------------------------------------------------------------------------------
  710. void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl )
  711. {
  712.     switch( nControlID )
  713.     {
  714.         case IDC_TOGGLEFULLSCREEN: DXUTToggleFullScreen(); break;
  715.         case IDC_TOGGLEREF:        DXUTToggleREF(); break;
  716.         case IDC_CHANGEDEVICE:     DXUTSetShowSettingsDialog( !DXUTGetShowSettingsDialog() ); break;
  717.         case IDC_DETAIL:
  718.             SetNumVertices( ((CDXUTSlider*)pControl)->GetValue() );
  719.             break;
  720.         case IDC_USEOPTIMIZED:
  721.             g_bShowOptimized = ((CDXUTCheckBox*)pControl)->GetChecked();
  722.             break;
  723.     }
  724. }
  725.  
  726.  
  727. //--------------------------------------------------------------------------------------
  728. // This callback function will be called immediately after the Direct3D device has 
  729. // entered a lost state and before IDirect3DDevice9::Reset is called. Resources created
  730. // in the OnResetDevice callback should be released here, which generally includes all 
  731. // D3DPOOL_DEFAULT resources. See the "Lost Devices" section of the documentation for 
  732. // information about lost devices.
  733. //--------------------------------------------------------------------------------------
  734. void CALLBACK OnLostDevice()
  735. {
  736.     if( g_pFont )
  737.         g_pFont->OnLostDevice();
  738.     if( g_pEffect )
  739.         g_pEffect->OnLostDevice();
  740.     SAFE_RELEASE(g_pTextSprite);
  741. }
  742.  
  743.  
  744. //--------------------------------------------------------------------------------------
  745. // This callback function will be called immediately after the Direct3D device has 
  746. // been destroyed, which generally happens as a result of application termination or 
  747. // windowed/full screen toggles. Resources created in the OnCreateDevice callback 
  748. // should be released here, which generally includes all D3DPOOL_MANAGED resources. 
  749. //--------------------------------------------------------------------------------------
  750. void CALLBACK OnDestroyDevice()
  751. {
  752.     SAFE_RELEASE(g_pEffect);
  753.     SAFE_RELEASE(g_pFont);
  754.  
  755.     for( UINT i = 0; i < g_dwNumMaterials; i++ )
  756.         SAFE_RELEASE( g_ppMeshTextures[i] );
  757.     SAFE_DELETE_ARRAY( g_ppMeshTextures );
  758.  
  759.     SAFE_RELEASE( g_pPMeshFull );
  760.     for( UINT i = 0; i < g_cPMeshes; i++ )
  761.         SAFE_RELEASE( g_ppPMeshes[i] );
  762.  
  763.     g_cPMeshes = 0;
  764.     delete[] g_ppPMeshes;
  765.  
  766.     SAFE_DELETE_ARRAY( g_mtrlMeshMaterials );
  767.     g_dwNumMaterials = 0;
  768. }
  769.